import { Body, Controller, Delete, Get, Param, ParseIntPipe, Post, Put, Req } from '@nestjs/common';
import { BaseController } from '../base/base.controller';
import { DbService } from '@app/db';
import { DeviceModel } from '@app/db/entities/DeviceModel';
import { FindOptionsWhere, In } from 'typeorm';
import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
import { DtoPipe } from '../pipes/dto/dto.pipe';
import { DeviceModelResult } from '../types/device-model.type';
import { PageDto, AddDto, UpdateDto } from './dto';

@Controller('deviceModel')
export class DeviceModelController extends BaseController {
    constructor(
        private readonly db:DbService
    ){
        super()
    }

    @Get('options')
    async options() {
        return this.successRes(await this.db.deviceModel.find(null, {id : true, name : true}))
    }

    @Post('page')
    async page(@Body() dto:PageDto, @Req() { locale }) {
       
        let result:PaginationResult<DeviceModelResult> = {
            total : 0,
            rows : []
        }

        let where:FindOptionsWhere<DeviceModel> = {
            
        }

        
        if(dto.name) {
            where.name = dto.name
        }

        result.total = await this.db.deviceModel.count(where)

        if(result.total > 0) {
            result.rows = await this.db.deviceModel.pagination(dto.pageNo, dto.pageSize, where, null, {id : 'DESC'})

            const ids:number[] = []

            if(result.rows.length > 0) {
                result.rows.forEach(row => {
                    if(row.settings) {
                        const settings = row.settings as number[]
                        settings.forEach(id => {
                            if(!ids.includes(id)) {
                                ids.push(id)
                            }
                        })
                    }

                    if(row.attrs) {
                        const attrs = row.attrs as number[]
                        attrs.forEach(id => {
                            if(!ids.includes(id)) {
                                ids.push(id)
                            }
                        })
                    }
                    
                })

                if(ids.length > 0) {
                    const attrs = await this.db.deviceSettingAttr.find({id : In(ids)}, ['id', 'name'])
                    const attrMap:{[key:string] : string} = {

                    }

                    attrs.forEach(attr => {
                        attrMap[attr.id] = attr.name
                    })

                    result.rows.forEach(row => {
                        if(row.settings) {
                            const settings = row.settings as number[]
                            row.settingNames = []
                            settings.forEach(id => {
                                row.settingNames.push(attrMap[id])
                            })
                        }

                        if(row.attrs) {
                            const attrs = row.attrs as number[]
                            row.attrNames = []
                            attrs.forEach(id => {
                                row.attrNames.push(attrMap[id])
                            })
                        }
    
                        
                    })

                }
 
            }

        }
        

        return this.successRes(result)

    }


    @Post('add')
    async add(@Body(new DtoPipe({skipMissingProperties : false})) dto:AddDto, @Req() { locale }) {

        
        const data:QueryDeepPartialEntity<DeviceModel> = {
            name : dto.name,
            createTime : this.utils.time(),
        }

        if(dto.attrs && dto.attrs.length > 0) {
            data.attrs = dto.attrs
        }

        if(dto.settings && dto.settings.length > 0) {
            data.settings = dto.settings
        }

        

        const res = await this.db.deviceModel.insert(data)
        return res ? this.successRes() : this.failRes()
    }


    @Put('update/:id')
    async update(@Body(new DtoPipe({skipNullProperties : true})) dto:UpdateDto, @Param('id', ParseIntPipe) id:number, @Req() { member, belong }) {
        if(id <= 0) return

        let fields = Object.keys(dto) as (keyof DeviceModel)[]
        if(fields.length == 0) return

        const deviceModel = await this.db.deviceModel.findOne({id : id}, fields)
        if(!deviceModel) return

        let updateData:KeyToValueType<DeviceModel> = {}
        for(let k in deviceModel) {
            if(k in dto && JSON.stringify(deviceModel[k]) != JSON.stringify(dto[k])) {
                updateData[k] = dto[k]
            }
        }

        if(Object.keys(updateData).length == 0) return this.successRes()

       

        updateData.updateTime = this.utils.time()


        const res = await this.db.deviceModel.update({id : id}, updateData)
        return res === 0 ? this.failRes() : this.successRes()
    }


    @Delete('delete/:id')
    async delete(@Param('id', ParseIntPipe) id:number) {
        if(id <= 0) return
        const res = await this.db.deviceModel.delete({id : id})
        return res === 0 ? this.failRes() : this.successRes()
    }
}
